using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
using Matrix.Configuration.Services;

namespace Matrix.Application.Services
{
    /// <summary>
    /// 幂等事件处理器实现
    /// 确保事件处理的幂等性，避免重复处理
    /// </summary>
    public class IdempotentEventProcessor : IIdempotentEventProcessor, ITransientDependency
    {
        private readonly ILogger<IdempotentEventProcessor> _logger;
        private readonly IDistributedCache _distributedCache;
        private readonly IClock _clock;
        private readonly IOptions<ConfigurationEventOptions> _options;
        private readonly IConfigurationEventMetrics _metrics;

        private const string EventProcessedPrefix = "config_event_processed:";
        private const string EventProcessingPrefix = "config_event_processing:";

        public IdempotentEventProcessor(
            ILogger<IdempotentEventProcessor> logger,
            IDistributedCache distributedCache,
            IClock clock,
            IOptions<ConfigurationEventOptions> options,
            IConfigurationEventMetrics metrics)
        {
            _logger = logger;
            _distributedCache = distributedCache;
            _clock = clock;
            _options = options;
            _metrics = metrics;
        }

        public async Task<bool> IsEventProcessedAsync(string eventId)
        {
            if (string.IsNullOrEmpty(eventId))
            {
                return false;
            }

            try
            {
                var cacheKey = GetProcessedCacheKey(eventId);
                var processedValue = await _distributedCache.GetStringAsync(cacheKey);

                var isProcessed = !string.IsNullOrEmpty(processedValue);
                _logger.LogDebug("检查事件处理状态: {EventId}, IsProcessed: {IsProcessed}",
                    eventId, isProcessed);

                return isProcessed;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "检查事件处理状态失败: {EventId}", eventId);
                // 在异常情况下，为了避免重复处理，返回true
                return true;
            }
        }

        public async Task MarkEventAsProcessedAsync(string eventId, TimeSpan? expiration = null)
        {
            if (string.IsNullOrEmpty(eventId))
            {
                return;
            }

            try
            {
                var cacheKey = GetProcessedCacheKey(eventId);
                var expirationTime = expiration ?? GetDefaultExpiration();

                var processedInfo = new EventProcessedInfo
                {
                    EventId = eventId,
                    ProcessedAt = _clock.Now,
                    ProcessorId = Environment.MachineName,
                    ProcessId = Environment.ProcessId
                };

                var serializedInfo = System.Text.Json.JsonSerializer.Serialize(processedInfo);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expirationTime };

                await _distributedCache.SetStringAsync(cacheKey, serializedInfo, options);

                // 清理处理中的标记
                var processingKey = GetProcessingCacheKey(eventId);
                await _distributedCache.RemoveAsync(processingKey);

                _logger.LogDebug("事件已标记为已处理: {EventId}, Expiration: {Expiration}",
                    eventId, expirationTime);

                // 记录指标
                _metrics.IncrementActiveEvents("IdempotentProcessed");
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "标记事件为已处理失败: {EventId}", eventId);
                throw;
            }
        }

        public async Task<bool> ProcessEventAsync(string eventId, Func<Task> handler)
        {
            if (string.IsNullOrEmpty(eventId))
            {
                throw new ArgumentException("事件ID不能为空", nameof(eventId));
            }

            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            var startTime = _clock.Now;

            try
            {
                // 检查事件是否已处理
                if (await IsEventProcessedAsync(eventId))
                {
                    _logger.LogDebug("事件已处理过，跳过: {EventId}", eventId);
                    return false;
                }

                // 尝试获取处理锁
                var lockAcquired = await TryAcquireProcessingLockAsync(eventId);
                if (!lockAcquired)
                {
                    _logger.LogDebug("获取事件处理锁失败，可能有其他实例正在处理: {EventId}", eventId);
                    return false;
                }

                try
                {
                    // 再次检查事件是否已处理（双重检查）
                    if (await IsEventProcessedAsync(eventId))
                    {
                        _logger.LogDebug("获取锁后发现事件已处理，跳过: {EventId}", eventId);
                        return false;
                    }

                    // 执行事件处理逻辑
                    await handler();

                    // 标记事件为已处理
                    await MarkEventAsProcessedAsync(eventId);

                    var duration = _clock.Now - startTime;
                    _logger.LogInformation("事件处理成功: {EventId}, Duration: {Duration}ms",
                        eventId, duration.TotalMilliseconds);

                    return true;
                }
                finally
                {
                    // 释放处理锁
                    await ReleaseProcessingLockAsync(eventId);
                }
            }
            catch (Exception ex)
            {
                var duration = _clock.Now - startTime;
                _logger.LogError(ex, "事件处理失败: {EventId}, Duration: {Duration}ms",
                    eventId, duration.TotalMilliseconds);
                throw;
            }
        }

        public async Task<T?> ProcessEventAsync<T>(string eventId, Func<Task<T>> handler) where T : class
        {
            if (string.IsNullOrEmpty(eventId))
            {
                throw new ArgumentException("事件ID不能为空", nameof(eventId));
            }

            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            var startTime = _clock.Now;

            try
            {
                // 检查事件是否已处理
                if (await IsEventProcessedAsync(eventId))
                {
                    _logger.LogDebug("事件已处理过，返回默认值: {EventId}", eventId);
                    return default(T);
                }

                // 尝试获取处理锁
                var lockAcquired = await TryAcquireProcessingLockAsync(eventId);
                if (!lockAcquired)
                {
                    _logger.LogDebug("获取事件处理锁失败，返回默认值: {EventId}", eventId);
                    return default(T);
                }

                try
                {
                    // 再次检查事件是否已处理
                    if (await IsEventProcessedAsync(eventId))
                    {
                        _logger.LogDebug("获取锁后发现事件已处理，返回默认值: {EventId}", eventId);
                        return default(T);
                    }

                    // 执行事件处理逻辑
                    var result = await handler();

                    // 标记事件为已处理
                    await MarkEventAsProcessedAsync(eventId);

                    var duration = _clock.Now - startTime;
                    _logger.LogInformation("带返回值的事件处理成功: {EventId}, Duration: {Duration}ms",
                        eventId, duration.TotalMilliseconds);

                    return result;
                }
                finally
                {
                    // 释放处理锁
                    await ReleaseProcessingLockAsync(eventId);
                }
            }
            catch (Exception ex)
            {
                var duration = _clock.Now - startTime;
                _logger.LogError(ex, "带返回值的事件处理失败: {EventId}, Duration: {Duration}ms",
                    eventId, duration.TotalMilliseconds);
                throw;
            }
        }

        public async Task CleanupExpiredRecordsAsync()
        {
            try
            {
                // 由于分布式缓存有TTL机制，这里主要清理处理锁
                // Redis会自动清理过期的键，这里不需要额外处理

                _logger.LogDebug("幂等事件处理过期记录清理完成");
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "清理过期事件处理记录失败");
            }
        }

        private async Task<bool> TryAcquireProcessingLockAsync(string eventId)
        {
            try
            {
                var lockKey = GetProcessingCacheKey(eventId);
                var lockValue = $"{Environment.MachineName}_{Environment.ProcessId}_{Guid.NewGuid():N}";
                var lockExpiration = TimeSpan.FromMinutes(5);

                // 使用Redis的SET命令的NX和EX选项实现分布式锁
                // 这里简化处理，实际应用中可以使用专门的分布式锁实现
                var existingValue = await _distributedCache.GetStringAsync(lockKey);

                if (string.IsNullOrEmpty(existingValue))
                {
                    var lockOptions = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = lockExpiration };
                    await _distributedCache.SetStringAsync(lockKey, lockValue, lockOptions);
                    _logger.LogDebug("获取事件处理锁成功: {EventId}, LockValue: {LockValue}",
                        eventId, lockValue);
                    return true;
                }
                else
                {
                    _logger.LogDebug("事件处理锁已被占用: {EventId}, ExistingValue: {ExistingValue}",
                        eventId, existingValue);
                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取事件处理锁异常: {EventId}", eventId);
                return false;
            }
        }

        private async Task ReleaseProcessingLockAsync(string eventId)
        {
            try
            {
                var lockKey = GetProcessingCacheKey(eventId);
                await _distributedCache.RemoveAsync(lockKey);

                _logger.LogDebug("释放事件处理锁: {EventId}", eventId);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "释放事件处理锁失败: {EventId}", eventId);
            }
        }

        private static string GetProcessedCacheKey(string eventId)
        {
            return $"{EventProcessedPrefix}{eventId}";
        }

        private static string GetProcessingCacheKey(string eventId)
        {
            return $"{EventProcessingPrefix}{eventId}";
        }

        private TimeSpan GetDefaultExpiration()
        {
            // 根据配置选项设置默认过期时间
            var retentionDays = _options.Value.MaxEventRetentionDays;
            return TimeSpan.FromDays(retentionDays);
        }

        /// <summary>
        /// 事件处理信息
        /// </summary>
        private class EventProcessedInfo
        {
            public string EventId { get; set; } = string.Empty;
            public DateTime ProcessedAt { get; set; }
            public string ProcessorId { get; set; } = string.Empty;
            public int ProcessId { get; set; }
        }
    }
}